package com.javasm.security;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.javasm.commons.util.Constants;
import com.javasm.commons.util.IpUtils;
import com.javasm.commons.util.ServletUtils;
import com.javasm.service.RedisService;
import com.javasm.sys.LoginUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import org.apache.tomcat.util.bcel.Const;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.SecretKey;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class TokenService {
    private String secret="mJlGmqkaQcnWGC6FIs+cRo5Tkzo9NCAEBOWnICam5WI=";  //令牌秘钥
    private Integer exp=30;//令牌有效期30分钟
    @Resource
    private RedisService redisService;

    public String createToken(LoginUser u) {
        String uuid = IdUtil.fastSimpleUUID();
        //设置当前登录用户唯一标识，作为redis的key与生成token的签名
        u.setUuid(uuid);
        //更新LoginUser中的登录时间与过期时间
        u.setLoginTime(System.currentTimeMillis());
        u.setExpireTime(u.getLoginTime()+exp*60*1000L);
        //解析User-agent请求头，设置登录ip，浏览器，操作系统；可省略
        setUserAgent(u);
        //LoginUser缓存redis，设置有效期
        saveCache(u);

        //生成返回客户端的token字符串
        Map map = new HashMap<>();
        map.put(Constants.UID,uuid);
        String s = generateToken(map);
        return s;
    }

    public void saveCache(LoginUser u){
        String key=Constants.LOGIN_USER+u.getUuid();
        redisService.set(key,u,exp,TimeUnit.MINUTES);
    }


    public void setUserAgent(LoginUser loginUser)
    {
        UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
        loginUser.setIp(ip);
        loginUser.setBrowser(userAgent.getBrowser().getName());
        loginUser.setOs(userAgent.getOs().getName()+"-"+userAgent.getOsVersion());
    }

    public String generateToken(Map<String, Object> claims){
        SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));
        String token = Jwts.builder()
                .setClaims(claims)
                .signWith(key).compact();
        return token;
    }

    public static void main(String[] args) {
        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        String secretString = Encoders.BASE64.encode(key.getEncoded());
        System.out.println(secretString);
    }


    public LoginUser getLoginUser(HttpServletRequest req) {
        String token = req.getHeader(Constants.ADMIN_TOKEN);
        if (StrUtil.isNotEmpty(token))
        {
            Claims claims = parseToken(token);
            // 解析对应的权限以及用户信息
            String uuid = (String) claims.get(Constants.UID);
            String userKey = Constants.LOGIN_USER+uuid;
            LoginUser user = (LoginUser) redisService.get(userKey);
            return user;
        }
        return null;
    }

    public Claims parseToken(String token){
        SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));
        return Jwts.parserBuilder()
                .setSigningKey(key).build()
                .parseClaimsJws(token)
                .getBody();
    }

    public void refreshToken(LoginUser u) {
        long oldExpireTime = u.getExpireTime();//获取超时时间
        long currentTime = System.currentTimeMillis();
        //小于20分钟，重置redis有效期为最大有效期
        if (oldExpireTime - currentTime <= 20 * 60 * 1000L)
        {
            u.setExpireTime(currentTime + exp * 60*1000L);
            saveCache(u);

        }
    }

    public void delLoginUser(String uuid) {
        if (StrUtil.isNotEmpty(uuid))
        {
            String userKey = Constants.LOGIN_USER+uuid;
            redisService.del(userKey);
        }
    }
}